require "lfs"
local unity=require "luaUnity"
local nl = require"luaNumeric"
require "unity"
require "luaMPI"


local LoadFekoRCS={
     get_settings_str = Gallop.get_settings_str;
     set_settings_str = Gallop.set_settings_str; 
};

----------------------------------------------------------------------------------------------------------------------------------------
--创建表和创建元表
function LoadFekoRCS:new (o)
	o = o or {};
	self.__index = self;
	setmetatable(o,self)
	self:init_str()
	self.init_RCSPost_func();
	return o;
end
----------------------------------------------------------------------------------------------------------------------------------------



--==============================================================================================================--
--初始化
function LoadFekoRCS:init_str ()
	-- 科学计数
	self.number = "[ ]*[+-]?%d+[.]?%d+[Ee+-]*%d*";

	-- FEKO out 文件中的频率
	self.freqStr = "Frequency in Hz:               FREQ =("..self.number..")";

	-- FEKO out 文件中的角度
	self.angleStr = "Direction of incidence:        THETA =("..self.number..")".."[ ]*PHI =("..self.number..")";   

	-- FEKO out 文件中的极化角
	self.polarStr = "Polarisation angle:            ETA =("..self.number..")";

	-- FEKO out 文件中的回波信息：scattering cross section后面的第二行
	self.rcsStr = "scattering cross section.-\n.-\n(.-)\n"
end
--==============================================================================================================--


--================================================================--
function LoadFekoRCS:init_RCSPost_func ()
	Gallop.RCSPost.inject_from_feko = function (self,rcs_data)	

		--print(rcs_data,#rcs_data);
		
		self.data = rcs_data;
		self.theta = nl.new_vector();
		self.phi = nl.new_vector();
		self.freqs = nl.new_vector();
		--self.fields_types = nl.new_vector();
		self.fields_types = {};
		self.rcssm = nl.new_vector();
		
		local ncols = #rcs_data;
		
		self.theta:reserve(ncols)
		self.phi:reserve(ncols)
		self.freqs:reserve(ncols)
		--self.fields_types:reserve(ncols)
		self.rcssm:reserve(ncols)
		--self.rcs:reserve(ncols)
		self.fields = {};
		self.listdata = {}

		for ii=1,ncols do
		
			ff = self.data[ii].freq;
			tt = self.data[ii].theta;
			pp = self.data[ii].phi;
			ftt = self.data[ii].polar;
			rcssm =self.data[ii].rcs
			
			self.freqs:push_back(ff);
			--self.fields_types:push_back(ftt);
			self.fields_types[ii] = ftt;
			self.theta:push_back(tt);
			self.phi:push_back(pp);
			self.rcssm:push_back(rcssm);
			
			local idx = self:generate_idx(ff,tt,pp,ftt)
			self.listdata[idx] = rcssm
			
			ftt = ftt..'-dB'
			self.fields_types[ii+ncols] = ftt;
			local idx = self:generate_idx(ff,tt,pp,ftt)
			self.listdata[idx] = 10*nl.log10(rcssm)
		end
		
---[[		
		self.theta_idx = self.Set (self.theta );
		self.phi_idx = self.Set (self.phi );
		self.freq_idx = self.Set (self.freqs );
		self.fields_type_idx = self.Set(self.fields_types);
		table.sort(self.theta_idx,function (a,b) return tonumber(a)<tonumber(b) end )
		table.sort(self.phi_idx,function (a,b) return tonumber(a)<tonumber(b) end )
		table.sort(self.freq_idx,function (a,b) return tonumber(a)<tonumber(b) end )
		
		self.freq_array = nl.new_vector();
		self.freq_array:reserve( #self.freq_idx );
		for k,v in pairs( self.freq_idx ) do
			self.freq_array:add(tonumber(v));
		end
		
		self.theta_array = nl.new_vector();
		self.theta_array:reserve( #self.theta_idx );
		for k,v in pairs( self.theta_array ) do
			self.theta_array:add(tonumber(v));
		end
		
		self.phi_array = nl.new_vector();
		self.phi_array:reserve( #self.phi_idx );
		for k,v in pairs( self.phi_array ) do
			self.phi_array:add(tonumber(v));
		end
		
		self:update_list_to_ui()
		
		for k,v in pairs(self.listdata) do
			--print(k,v)
		end
--]]
	end	
end
--================================================================--

--==============================================================================================================--
--读取feko文件
function LoadFekoRCS:read_feko_out_file_ui (path)
	self:read_feko_out_file (path)
	self.opath = strippath(path)..'/'..getFilenameWithoutExt(path)..'/';
	unity.mkdir( self.opath );
	self:write_rcs_to_file(self.opath..'rcs.txt');	
	self:update_results_data_to_tableview_ui();
end
--==============================================================================================================--


--==============================================================================================================--
--读取feko文件
function LoadFekoRCS:read_feko_out_file (path)

	----------------------------------------------------------------------------------------------------------
	function mysplit(s, delimiter)
		result = {};
		for match in (s..delimiter):gmatch("%s*(.-)%s*"..delimiter.."+") do
		    table.insert(result, match);
		end
		return result;
	end
	----------------------------------------------------------------------------------------------------------

	self.rcs_data={};
	local file = io.open( path,"r");
	assert( file, "Open file failed, path: "..path);
	
	local str = file:read("*a")
	for freq,theta,phi,polar,rcs in string.gmatch(str,self.freqStr..".-"..self.angleStr..".-"..self.polarStr..".-"..self.rcsStr) do
	      data = {};
	      data.freq = tonumber(freq)/1e9
	      data.theta = 90-tonumber(theta)
	      data.phi = tonumber(phi)
	      data.polar = tonumber(polar)
	      --print(rcs)
	      rcs_table = mysplit(rcs, ' ')
	      data.rcs = tonumber(rcs_table[7])
	      data.dbrcs = 10*nl.log10(data.rcs)
	      table.insert(self.rcs_data,data)
	 end
	 file:close()    
end
--==============================================================================================================--

--==============================================================================================================--
--保存结果文件
function LoadFekoRCS:write_rcs_to_file (path)
	local fileOut = io.open( path,"w");
	assert( fileOut, "Open file failed, path: "..path);

	fileOut:write( "Freq[GHz]\tpolar[deg]\ttheta[deg]\tphi[deg]\trcs[sm]\trcs[dBsm]\n" );
	for _,data in pairs( self.rcs_data ) do
		fileOut:write( data.freq,"\t" );
		fileOut:write( data.polar,"\t" );
		fileOut:write( data.theta,"\t" );
		fileOut:write( data.phi,"\t" );
		fileOut:write( data.rcs,"\n" );
		fileOut:write( data.dbrcs,"\n" );
	end
	fileOut:close()
end
--==============================================================================================================--


--==============================================================================================================--
--从模块中获取结果到 res和labels
function LoadFekoRCS:get_data(res,labels)
	labels:clear();
	labels:add('Freq[GHz]')
	labels:add('Polar angle[°]')
	labels:add('仰角[°]')
	labels:add('舷角[°]')
	labels:add('单站RCS[sm]')
	labels:add('单站RCS[dBsm]')
	res:resize( #self.rcs_data,6 );	
	for ii,data in pairs( self.rcs_data ) do
		res[{ii,1}] = data.freq;
		res[{ii,2}] = data.polar;
		res[{ii,3}] = data.theta;
		res[{ii,4}] = data.phi;
		res[{ii,5}] = data.rcs;
		res[{ii,6}] = data.dbrcs;
	end	
end
--==============================================================================================================--

--==============================================================================================================--
--设置数据
function LoadFekoRCS:set_data(res)
	local nrows = res:rows();
	local ncols = res:cols();
	assert(ncols==5, 'coloums do not match')
	self.rcs_data={};	
	for ii = 1,nrows  do
		self.rcs_data[ii] = { freq = res[{ii,1}];
						polar = res[{ii,2}];
						theta = res[{ii,3}];
						phi = res[{ii,4}];
						rcs = res[{ii,5}]; };
	end	
end
--==============================================================================================================--

--==============================================================================================================--
function cal_generic_rcs(x1,y1)
	
	local sum = 0;
	local num = 0;
	for ii=1,#x1 do
		if nl.abs( nl.wrap_phase_deg(x1[ii]*4)/4 ) > 4.5 then
			sum = sum+y1[ii]
			num = num + 1;
		end
	end
	sum = sum/num
	return sum;
end
--==============================================================================================================--

--==============================================================================================================--
function cal_generic_rcs_array(x1,y1,name)
	x2 = nl.new_vector();
	y2 = nl.new_vector();
	x2:reserve(#x1)
	local sum = 0;
	local num = 0;
	for ii=1,#x1 do
		if nl.abs( nl.wrap_phase_deg(x1[ii]*4)/4 ) > 4.5 then
			sum = sum+y1[ii]
			num = num + 1;
			x2:add(x1[ii])
		end
	end

	y2:resize(#x2)
	sum = sum/num
	for ii=1,#x2 do
		y2[ii] = sum;
	end
	return x2,y2,'General RCS of "'..name..'" [val='..string.format("%.2f", sum)..' sm]';
end
--==============================================================================================================--

--==============================================================================================================--
function feko_rcs_add_phi_curves(self,freqs,thetas,phis,fts)

	if  self.view then
		local n = #freqs * #thetas * #fts;
		local xx = nl.new_vector(#self.phi_idx);
		local yys ={}
		local lables={}
		for ii=1,n do
		    yys[ii] = nl.new_vector( #self.phi_idx );
		end
		
		jj=1;
		for f,ff in pairs(freqs) do
			for t,tt in pairs(thetas) do
				for ft,ftt in pairs(fts) do
					idx = "";
					--if #freqs * #thetas * #fts == 1 then
						idx =  idx .. "频率[" ..ff .. " GHz]";
					--end
					--if #freqs > 1 then idx =  idx .. "频率[" ..ff .. " GHz] " end
					if #thetas > 1 then idx =  idx .. ",仰角[" ..tt .. "°] " end
					if #fts > 1 then idx =  idx .. ", 极化角[" ..ftt .. "]" end
					lables[jj] = idx;
					jj = jj+1;
				end
			end
		end

		for p,pp in pairs( self.phi_idx ) do
			xx[p] = tonumber(pp);
			jj=1;
			for f,ff in pairs(freqs) do
				for t,tt in pairs(thetas) do
					for ft,ftt in pairs(fts) do
						idx = tt .." ";
						idx = idx .. pp .." ";
						idx = idx .. ftt .." ";
						idx = idx .. ff;
						local idx1 = self:generate_idx(ff,tt,pp,ftt)

						print(jj,p, idx,idx1,self.listdata[ idx1 ],self.listdata[ idx ])
						yys[jj][p] = tonumber( self.listdata[ idx ] );
						--print(jj,p,yys[jj][p])
						jj = jj+1;
					end
				end
			end
		end

		self:init_angle_phi_spectrum_plot();

		for ii=1,n do
		     local gp = self.view:addGraph(xx,yys[ii],lables[ii])	  
		end	
		for ii=1,n do
		     x2,y2,name = cal_generic_rcs_array(xx,yys[ii],lables[ii])  
		     self.view:addGraph(x2,y2,name);
		end	
		self.view:rescaleAxes();
	end
	
end
--==============================================================================================================--


--==============================================================================================================--
function feko_rcs_add_freq_curves(self,freqs,thetas,phis,fts)

	-- print_table(thetas);
	-- print_table(phis);
	-- print_table(fts);
	
	local n = #thetas * #phis * #fts;
	local xx = nl.new_vector(#self.freq_idx);
	local yys ={}
	local lables={}
	for ii=1,n do
	    yys[ii] = nl.new_vector( #self.freq_idx );
	end
	
	jj=1;
	for t,tt in pairs(thetas) do
		for p,pp in pairs(phis) do
			for ft,ftt in pairs(fts) do
				idx = "";
				if #thetas > 1 then idx =  idx .. "仰角[" ..tt .. " °] " end
				if #phis > 1 then idx =  idx .. "Phi[" ..pp .. "] " end
				if #fts > 1 then idx =  idx .. "[" ..ftt .. "]" end
				lables[jj] = idx;
				jj = jj+1;
			end
		end
	end

	for f,ff in pairs( self.freq_idx ) do
		xx[f] = tonumber(ff);
		jj=1;
		for t,tt in pairs(thetas) do
			for p,pp in pairs(phis) do
				for ft,ftt in pairs(fts) do
					idx = tt .." ";
					idx = idx .. pp .." ";
					idx = idx .. ftt .." ";
					idx = idx .. ff;
					yys[jj][f] = tonumber( self.listdata[ idx ] );
					jj = jj+1;
				end
			end
		end
	end

	self:init_freq_spectrum_plot();

	for ii=1,n do
	     local gp = self.view:addGraph(xx,yys[ii],lables[ii])	    
	end		
	self.view:rescaleAxes();
end
--==============================================================================================================--


--==============================================================================================================--
--计算平均RCS
function feko_rcs_cal_general_rcs(self,freqs,thetas,phis,fts)

	local n = #freqs * #thetas * #fts;
	local xx = nl.new_vector(#self.phi_idx);
	local yys ={}
	local fts1 ={}
	for ii=1,n do
	    yys[ii] = nl.new_vector( #self.phi_idx );
	end

	for p,pp in pairs( self.phi_idx ) do
		xx[p] = tonumber(pp);
		jj=1;
		for f,ff in pairs(freqs) do
			for t,tt in pairs(thetas) do
				for ft,ftt in pairs(fts) do
					idx = tt .." ";
					idx = idx .. pp .." ";
					idx = idx .. ftt .." ";
					idx = idx .. ff;
					local idx1 = self:generate_idx(ff,tt,pp,ftt)
					yys[jj][p] = tonumber( self.listdata[ idx ] );
					jj = jj+1;
				end
			end
		end
	end
	
	local grcs = {};	
	for ii=1,n do
		grcs[ii] = cal_generic_rcs(xx,yys[ii]);
	end	
		
	self.listdata = {}
	for f,ff in pairs(freqs) do
		for t,tt in pairs(thetas) do
			for ft,ftt in pairs(fts) do
				local idx1 = self:generate_idx(ff,tt,pp,ftt..'-General RCS')
				self.listdata[ idx ] = grcs[ii];
				jj = jj+1;
			end
		end
	end
	
	jj=1;
	for f,ff in pairs(freqs) do
		for t,tt in pairs(thetas) do
			for ft,ftt in pairs(fts) do
				fts1[ft] = ftt..'-General RCS'
				local idx1 = self:generate_idx(ff,tt,'0.0',ftt..'-General RCS')
				self.listdata[ idx1 ] = grcs[jj];	
				print(idx1, grcs[jj])
				jj = jj+1;
			end
		end
	end
	self.freq_idx = freqs;
	self.theta_idx = thetas;
	self.phi_idx = {'0.0'};
	self.fields_type_idx = fts1;
	self:update_list_to_ui()
end
--==============================================================================================================--


--==============================================================================================================--
--导出图片
function LoadFekoRCS:export_figs ()
	--初始化视图
	if not Gallop.RCSPost.view then 
		Gallop.RCSPost:add_view()		
		Gallop.RCSPost:update_selections_to_ui ( 2,Gallop.RCSPost.freq_idx,
								    {Gallop.RCSPost.theta_idx[1]},
								    {Gallop.RCSPost.phi_idx[1]},
								    {Gallop.RCSPost.fields_type_idx[1]} );
	end
	
	--获取视图选项
	freqs, thetas, phis, fts = Gallop.RCSPost:update_selections_from_ui();
	
	--设置并保存视图坐标轴信息
	local fun = Gallop.RCSPost.init_angle_phi_spectrum_plot;
	function Gallop.RCSPost:init_angle_phi_spectrum_plot()
		if self.view then
			self.view.xAxis:setProperty( {name="舷角 φ [°]"} )
			self.view.yAxis:setProperty( {name="雷达散射截面 RCS [sm]"} )
			self.view:rescaleAxes();
		end
	end
	local funplot = Gallop.RCSPost.add_phi_curves;
	Gallop.RCSPost.add_phi_curves = feko_rcs_add_phi_curves;
	
	--画图并导出
	for k,v in pairs ( freqs ) do 
		Gallop.RCSPost:clear_curves();
		Gallop.RCSPost:add_curves( 2, {v},
						thetas,
						phis,
						fts);
		Gallop.RCSPost.view:savePng( self.opath .. v .. '.png' )
	end
	
	--还原视图信息
	Gallop.RCSPost.init_angle_phi_spectrum_plot = fun;
	Gallop.RCSPost.add_phi_curves = funplot;
end
--==============================================================================================================--

--==============================================================================================================--
--注入结果
function LoadFekoRCS:inject ()
	self:update_tableview_data_to_module();
	Gallop.RCSPost:inject_from_feko(self.rcs_data);
end
--==============================================================================================================--

--==============================================================================================================--
--注入结果
function LoadFekoRCS:transform ()
		--初始化视图
	if not Gallop.RCSPost.view then 
		Gallop.RCSPost:add_view()		
		Gallop.RCSPost:update_selections_to_ui ( 2,Gallop.RCSPost.freq_idx,
								    {Gallop.RCSPost.theta_idx[1]},
								    {Gallop.RCSPost.phi_idx[1]},
								    {Gallop.RCSPost.fields_type_idx[1]} );
	end
	
	--获取视图选项
	freqs, thetas, phis, fts = Gallop.RCSPost:update_selections_from_ui();
	
	Gallop.RCSPost.transform = feko_rcs_cal_general_rcs;
	Gallop.RCSPost:transform(freqs, thetas, phis, fts)
	Gallop.RCSPost.add_freq_curves = feko_rcs_add_freq_curves;
end
--==============================================================================================================--


return LoadFekoRCS;
